package io.coderyeah.ymcc.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.coderyeah.ymcc.constant.RedisConstants;
import io.coderyeah.ymcc.constant.YmccConstants;
import io.coderyeah.ymcc.domain.Login;
import io.coderyeah.ymcc.domain.User;
import io.coderyeah.ymcc.domain.UserAccount;
import io.coderyeah.ymcc.domain.UserBaseInfo;
import io.coderyeah.ymcc.dto.RegisterDTO;
import io.coderyeah.ymcc.enums.YmccSystemError;
import io.coderyeah.ymcc.exception.BusinessException;
import io.coderyeah.ymcc.feign.client.LoginServiceClient;
import io.coderyeah.ymcc.mapper.UserAccountMapper;
import io.coderyeah.ymcc.mapper.UserBaseInfoMapper;
import io.coderyeah.ymcc.mapper.UserMapper;
import io.coderyeah.ymcc.result.JSONResult;
import io.coderyeah.ymcc.service.IUserService;
import io.coderyeah.ymcc.util.BitStatesUtils;
import io.coderyeah.ymcc.util.QRCode;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.File;
import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author coderyeah
 * @since 2022-10-19
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private LoginServiceClient loginServiceClient;
    @Autowired
    private UserAccountMapper accountMapper;
    @Autowired
    private UserBaseInfoMapper baseInfoMapper;

    @Override
    @GlobalTransactional(rollbackFor = Exception.class) //开启Seata全局事务
    public JSONResult register(RegisterDTO registerDTO) {
        // 校验数据
        checkData(registerDTO);
        // 封装login对象用于保存用户登录认证信息
        Login login = user2login(registerDTO);
        // 服务调用
        JSONResult result = loginServiceClient.saveOrUpdate(login);
        Long loginId = Long.valueOf(result.getData().toString());
        // 添加数据
        User newUSer = registerDTO2User(registerDTO);
        newUSer.setLoginId(loginId);
        userMapper.insert(newUSer);
        // 添加账户信息
        addUserAccount(newUSer);
        // 添加用户基本信息
        final UserBaseInfo userBaseInfo = addBaseInfo(newUSer, registerDTO);
        baseInfoMapper.insert(userBaseInfo);
        // 删除redis中验证码
        final String value = stringRedisTemplate.opsForValue().get(YmccConstants.REGISTER_CODE + registerDTO.getMobile());
        if (value != null) {
            stringRedisTemplate.delete(YmccConstants.REGISTER_CODE + registerDTO.getMobile());
        }
        return JSONResult.success();
    }

    private UserBaseInfo addBaseInfo(User newUSer, RegisterDTO registerDTO) {
        final UserBaseInfo userBaseInfo = new UserBaseInfo();
        // 是否有推荐人
        if (StrUtil.isNotBlank(registerDTO.getRecommendationCode())) {
            // 从redis 获取数据
            String value = stringRedisTemplate.opsForValue().get(RedisConstants.USER_RECOMMEND_CODE + registerDTO.getRecommendationCode());
            if (value == null) {
                throw new BusinessException(YmccSystemError.RECOMMEND_CODE_EXPIRED);
            }
            // 获取推荐人用户id
            userBaseInfo.setReferId(Long.valueOf(value));
        }
        userBaseInfo.setCreateTime(new Date().getTime());
        userBaseInfo.setId(newUSer.getId());
        userBaseInfo.setLevel(UserBaseInfo.LEVEL);
        userBaseInfo.setRegChannel(UserBaseInfo.REG_WEB);
        userBaseInfo.setGrowScore(UserBaseInfo.GROW_SCORE);
        return userBaseInfo;
    }

    private void addUserAccount(User newUSer) {
        final UserAccount userAccount = new UserAccount();
        userAccount.setCreateTime(new Date().getTime());
        userAccount.setId(newUSer.getId());
        userAccount.setPassword(DigestUtil.md5Hex("123456"));
        userAccount.setUsableAmount(new BigDecimal("0"));
        userAccount.setFrozenAmount(new BigDecimal("0"));
        accountMapper.insert(userAccount);
    }

    private void checkData(RegisterDTO registerDTO) {
//        Object imageCodeValue = redisTemplate.opsForValue().get(registerDTO.getImageCodeKey());
//        if (!imageCodeValue.equals(registerDTO.getImageCode())){
//            // 图形验证码错误
//            throw new BusinessException(YmccSystemError.IMAGE_CODE_ERROR);
//        }
        String value = stringRedisTemplate.opsForValue().get(YmccConstants.REGISTER_CODE + registerDTO.getMobile());
        if (value == null) {
            // 验证码过期
            throw new BusinessException(YmccSystemError.VERIFICATION_CODE_EXPIRED);
        }
        // 判断短信验证码是否正确
        final String code = value.split(":")[0];
        if (!registerDTO.getSmsCode().equals(code)) {
            throw new BusinessException(YmccSystemError.VERIFICATION_CODE_ERROR);
        }
        // 查看数据库是否已经存在
        final User user2 = getUser(registerDTO);
        if (user2 != null) {
            // 用户已经存在 请勿重复注册
            throw new BusinessException(YmccSystemError.USER_EXISTS);
        }
    }

    private User getUser(RegisterDTO registerDTO) {
        final User user = new User();
        user.setPhone(registerDTO.getMobile());
        return userMapper.selectOne(user);
    }

    private Login user2login(RegisterDTO registerDTO) {
        final Login login = new Login();
        login.setPassword(DigestUtil.md5Hex(registerDTO.getPassword()));
        login.setUsername(registerDTO.getMobile());
        login.setEnabled(true);
        login.setType(1);
        login.setClientId("website");
        login.setAccountNonExpired(true);
        login.setAccountNonLocked(true);
        login.setCredentialsNonExpired(true);
        return login;
    }

    private User registerDTO2User(RegisterDTO registerDTO) {
        final User user = new User();
        user.setPhone(registerDTO.getMobile());
        user.setCreateTime(System.currentTimeMillis());
        user.setNickName(registerDTO.getMobile());
        long state = BitStatesUtils.addState(BitStatesUtils.OP_ACTIVED, BitStatesUtils.OP_REGISTED);
        long addState = BitStatesUtils.addState(state, BitStatesUtils.OP_AUTHED_PHONE);
        user.setBitState(addState);
        return user;
    }

    @Override
    public JSONResult getRecommendedLink() {
        StringBuffer url = new StringBuffer("http://127.0.0.1:6003/reg.phone.html?recommendationCode=");
        // 获取登录用户 指定为id为1L
        long userId = 1L;
        String path = "D:/Qrcode/code" + userId + ".jpg";
        // 生成随机推荐码
        String code = RandomUtil.randomString(6);
        url.append(code);
        log.info("推荐码：{}", code);
        log.info("url：{}", url);
        log.info("path：{}", path);
        // 存入redis 有效期3分钟
        stringRedisTemplate.opsForValue().set(RedisConstants.USER_RECOMMEND_CODE + code, String.valueOf(userId), RedisConstants.EXPIRE_TIME, TimeUnit.MINUTES);
        // 生成验证码
        boolean b = QRCode.qrCode(url.toString(), path);
        if (b) {
            log.info("二维码生成成功");
        }
        // 用图片生成base64编码
        String encode = Base64.encode(new File(path));
        return JSONResult.success(code, encode);
    }
}
